/* XXX DOES NOT USE BUILT-IN DETECTION FUNCTION XXX
alert tcp $EXTERNAL_NET any -> $HOME_NET 445 (msg:"NETBIOS SMB server srvnet.sys driver race condition attempt"; flow:to_server,established; content:"|FF|SMB|72|"; offset:4; depth:5; isdataat:30,relative; byte_jump:1,27,relative,multiplier 2; metadata:policy balanced-ips drop, policy security-ips drop, service netbios-ssn; classtype:attempted-dos; reference:cve,2010-0021; reference:url,technet.microsoft.com/en-us/security/bulletin/MS10-0120; sid:16396;)
*/
/*
 * Use at your own risk.
 *
 * Copyright (C) 2005-2008 Sourcefire, Inc.
 * 
 * This file is autogenerated via rules2c, by Brian Caswell <bmc@sourcefire.com>
 */


#include "sf_snort_plugin_api.h"
#include "sf_snort_packet.h"

#include "so-util.h"

/* declare detection functions */
int rule16396eval(void *p);

/* declare rule data structures */
/* flow:established, to_server; */
static FlowFlags rule16396flow0 = 
{
    FLOW_ESTABLISHED|FLOW_TO_SERVER
};

static RuleOption rule16396option0 =
{
    OPTION_TYPE_FLOWFLAGS,
    {
        &rule16396flow0
    }
};
#ifndef CONTENT_FAST_PATTERN
#define CONTENT_FAST_PATTERN 0
#endif
// content:"|FF|SMBr", offset 4, depth 5, fast_pattern; 
static ContentInfo rule16396content1 = 
{
    (uint8_t *) "|FF|SMBr", /* pattern (now in snort content format) */
    5, /* depth */
    4, /* offset */
    CONTENT_FAST_PATTERN|CONTENT_BUF_NORMALIZED, /* flags */
    NULL, /* holder for boyer/moore PTR */
    NULL, /* more holder info - byteform */
    0, /* byteform length */
    0 /* increment length*/
};

static RuleOption rule16396option1 = 
{
    OPTION_TYPE_CONTENT,
    {
        &rule16396content1
    }
};

/* references for sid 16396 */
/* reference: cve "2010-0021"; */
static RuleReference rule16396ref1 = 
{
    "cve", /* type */
    "2010-0021" /* value */
};

/* reference: url "technet.microsoft.com/en-us/security/bulletin/MS10-0120"; */
static RuleReference rule16396ref2 = 
{
    "url", /* type */
    "technet.microsoft.com/en-us/security/bulletin/MS10-012" /* value */
};

static RuleReference *rule16396refs[] =
{
    &rule16396ref1,
    &rule16396ref2,
    NULL
};
/* metadata for sid 16396 */
/* metadata:service netbios-ssn, policy balanced-ips drop, policy security-ips drop; */
static RuleMetaData rule16396service1 = 
{
    "service netbios-ssn"
};


//static RuleMetaData rule16396policy1 = 
//{
//    "policy balanced-ips drop"
//};
//
//static RuleMetaData rule16396policy2 = 
//{
//    "policy security-ips drop"
//};


static RuleMetaData *rule16396metadata[] =
{
    &rule16396service1,
//    &rule16396policy1,
//    &rule16396policy2,
    NULL
};

RuleOption *rule16396options[] =
{
    &rule16396option0,
    &rule16396option1,
//    &rule16396option2,
//    &rule16396option3,
    NULL
};

Rule rule16396 = {
   /* rule header, akin to => tcp any any -> any any */
   {
       IPPROTO_TCP, /* proto */
       "$EXTERNAL_NET", /* SRCIP     */
       "any", /* SRCPORT   */
   
       0, /* DIRECTION */
       "$HOME_NET", /* DSTIP     */
   
       "445", /* DSTPORT   */
   },
   /* metadata */
   { 
       3,  /* genid */
       16396, /* sigid */
       5, /* revision */
       "attempted-dos", /* classification */
       0,  /* hardcoded priority XXX NOT PROVIDED BY GRAMMAR YET! */
       "NETBIOS SMB server srvnet.sys driver race condition attempt",     /* message */
       rule16396refs /* ptr to references */
       ,rule16396metadata
   },
   rule16396options, /* ptr to rule options */
   &rule16396eval, /* use the built in detection function */
   0 /* am I initialized yet? */
};


/* detection functions */
int rule16396eval(void *p) {
    const uint8_t *cursor_normal = 0;
    SFSnortPacket *sp = (SFSnortPacket *) p;

    const uint8_t *beg_of_payload, *end_of_payload;
    uint32_t length = 0;
    uint16_t WCT;
    uint16_t BCC;

    if(sp == NULL)
        return RULE_NOMATCH;

    if(sp->payload == NULL)
        return RULE_NOMATCH;
    
    // flow:established, to_server;
    if (checkFlow(p, rule16396options[0]->option_u.flowFlags) > 0 ) {
        // content:"|FF|SMBr", offset 4, depth 5, fast_pattern;
        if (contentMatch(p, rule16396options[1]->option_u.content, &cursor_normal) > 0) {

            if(getBuffer(sp, CONTENT_BUF_NORMALIZED, &beg_of_payload, &end_of_payload) <= 0)
                     return RULE_NOMATCH;

            // isdataat:offset 30, relative;
            if (cursor_normal + 30 <= end_of_payload) {

                //Extract length from Netbios session header
                //Previous content match assures us no buffer underread
                length = *(cursor_normal-8) << 16;
                length |= *(cursor_normal-7) << 8;
                length |= *(cursor_normal-6);

                //Extract WCT Word Count
                //Word Count should be usually be zero in negotiate requests
                //But we need to be able to handle the case where there is 
                //some value in there.
                cursor_normal += 27;
                WCT =  2 * *cursor_normal++;
                cursor_normal += WCT;                

                //Make sure there is enough room to extract BCC
                if (cursor_normal + 2 > end_of_payload)
                    return RULE_NOMATCH;

                //Extract BCC Byte Count
                BCC = read_little_16_inc(cursor_normal);

                //Alert if your netbios session size is bigger than
                //Byte count + number of words * 2 + 32-byte SMB header
                //+ 3 bytes (1 for the WCT field, and 2 for the BCC field)
                if (length > (BCC + WCT + 35))
                    return RULE_MATCH;
            }
        }
    }
    return RULE_NOMATCH;
}

/*
Rule *rules[] = {
    &rule16396,
    NULL
};
*/


